/**
 * 
 */
package com.p2p.front.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.p2p.base.exception.BizException;
import com.p2p.base.model.Money;
import com.p2p.base.page.PageVo;
import com.p2p.base.util.DateUtil;
import com.p2p.front.component.TenderPointSetting;
import com.p2p.front.dal.dao.LoanInfoDao;
import com.p2p.front.dal.dao.MemberPointDao;
import com.p2p.front.dal.dao.TenderDao;
import com.p2p.front.dal.dao.TransferDao;
import com.p2p.front.dal.dao.UserDao;
import com.p2p.front.dal.model.LoanInfo;
import com.p2p.front.dal.model.MemberPoint;
import com.p2p.front.dal.model.MemberPointLog;
import com.p2p.front.dal.model.SysConfig;
import com.p2p.front.dal.model.SysConfig.ConfigKeyEnum;
import com.p2p.front.dal.model.Tender;
import com.p2p.front.dal.model.TenderReturn;
import com.p2p.front.dal.model.TenderReturn.ReturnType;
import com.p2p.front.dal.model.Transfer;
import com.p2p.front.dal.model.User;
import com.p2p.front.enums.CanTransferStatus;
import com.p2p.front.enums.ChargeType;
import com.p2p.front.enums.TenderReturnStatus;
import com.p2p.front.enums.TenderStatus;
import com.p2p.front.enums.TenderTstatus;
import com.p2p.front.enums.TransferStatus;
import com.p2p.front.result.TransferResult;
import com.p2p.front.service.ChargeService;
import com.p2p.front.service.CommonService;
import com.p2p.front.service.LoanInfoService;
import com.p2p.front.service.MemberPointService;
import com.p2p.front.service.SysConfigService;
import com.p2p.front.service.TenderReturnService;
import com.p2p.front.service.TenderService;
import com.p2p.front.service.TransferService;
import com.p2p.front.service.UserService;
import com.p2p.trans.client.enums.SubTransCodeEnum;
import com.p2p.trans.client.enums.TransCodeEnum;
import com.p2p.trans.client.facade.AccountQueryFacade;
import com.p2p.trans.client.facade.AccountTransFacade;
import com.p2p.trans.client.model.AccountVO;
import com.p2p.trans.client.model.TransInfo;
import com.p2p.trans.client.result.AccountQueryResult;
import com.p2p.trans.client.result.AccountTransResult;

/**
 * @author ruiqi
 *
 */
@Service("transferService")
public class TransferServiceImpl implements TransferService {
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Resource
	private TransferDao transferDao;

	@Resource
	private LoanInfoDao loanInfoDao;

	@Resource
	private TenderService tenderService;

	@Resource
	private TenderDao tenderDao;

	@Resource
	private TenderReturnService tenderReturnService;

	@Resource
	private AccountTransFacade remoteAccountTransFacade;

	@Resource
	private AccountQueryFacade remoteAccountQueryFacade;

	@Resource
	private PlatformTransactionManager transactionManager;

	@Resource
	private LoanInfoService loanInfoService;

	@Autowired
	private UserDao userDao;

	/*@Resource
	private MemberPointDao memberPointDao;*/
	
	@Resource
	private MemberPointService memberPointService;

	@Resource
	private CommonService commonService;
	@Resource
	private ChargeService chargeService;

	@Resource
	private UserService userService;
	@Resource
	private TenderPointSetting tenderPointSetting;
	@Resource
	private SysConfigService sysConfigService;

	@Override
	public Transfer getTransfer(Transfer transfer) {
		return transferDao.getTransfer(transfer);
	}

	@Override
	public Transfer getTransferForUpdate(Transfer transfer) {
		return transferDao.getTransferForUpdate(transfer);
	}

	// 能否转让
	public boolean canTransferFast(Long uid, Long tid) {
		boolean can = true;
		// tender回收中，status和tstatus
		Tender tender = tenderService.getByTidAndUid(tid, uid);
		if (tender == null) {
			throw new BizException("", "系统内部错误");
		}
		boolean tenderOk = tender.getStatus() == 21 && tender.getTstatus() == 0;
		if (!tenderOk) {
			return false;
		}

		Date now = new Date();
		// tender-return还款列表，未还款的，是否存在“逾期”,是否存在“当天”
		List<TenderReturn> tenderReturnList = recyclingTenderReturn(
				tender.getUid(), tender.getTid());
		if (tenderReturnList.size() == 0) {
			return false;
		}
		Date date = tenderReturnList.get(0).getTime();

		boolean sameDay = DateUtil.isSameDay(date, now);
		// 计息日、还款日，当天不能转
		if (sameDay) {
			return false;
		}
		// 逾期
		boolean late = now.getTime() > date.getTime();
		if (late) {
			return false;
		}

		// 投标当天不能转
		Date addtime = tender.getAddtime();
		Date bidtime = tender.getBidtime();
		boolean tenderSameDay = DateUtil.isSameDay(addtime, now)
				|| DateUtil.isSameDay(bidtime, now);
		if (tenderSameDay) {
			return false;
		}

		return can;
	}

	// 能否转让
	public CanTransferStatus canTransferVeryStrict(Long uid, Long tid) {
		// tender回收中，status和tstatus
		Tender tender = tenderService.getByTidAndUid(tid, uid);
		if (tender == null) {
			throw new BizException("", "系统内部错误");
		}
		boolean tenderOk = tender.getStatus() == 21 && tender.getTstatus() == 0;
		if (!tenderOk) {
			return CanTransferStatus.TENDER_ERROR;
		}
		// 是否正在转让,transfer的tid和status
		Integer count = transferDao.count(tid,
				TransferStatus.TRANSFERING.getCode());
		if (count > 0) {
			return CanTransferStatus.TRANSFERING;
		}

		Date now = new Date();
		// tender-return还款列表，未还款的，是否存在“逾期”,是否存在“当天”
		List<TenderReturn> tenderReturnList = recyclingTenderReturn(
				tender.getUid(), tender.getTid());
		for (TenderReturn tenderReturn : tenderReturnList) {
			Date date = tenderReturn.getTime();

			boolean sameDay = DateUtil.isSameDay(date, now);
			// 计息日、还款日，当天不能转
			if (sameDay) {
				return CanTransferStatus.SAME_DAY;
			}
			// 逾期
			boolean late = now.getTime() > date.getTime();
			if (late) {
				return CanTransferStatus.LATE;
			}
		}
		// 投标当天不能转
		Date addtime = tender.getAddtime();
		Date bidtime = tender.getBidtime();
		boolean tenderSameDay = DateUtil.isSameDay(addtime, now)
				|| DateUtil.isSameDay(bidtime, now);
		if (tenderSameDay) {
			return CanTransferStatus.SAME_DAY;
		}
		Transfer transfer = new Transfer();
		updateTransferPrincipalInterestNum(transfer, tenderReturnList);
		// 积分够不够
		MemberPoint memberPoint = memberPointService.getUserMemberPoint(uid+"");
		Money principal = transfer.getTransPrincipal();
		if (!isMemberPointEnough(memberPoint, principal,tenderReturnList.size())) {
			return CanTransferStatus.MEMBER_POINT_NOT_ENOUGH;
		}
		return CanTransferStatus.OK;
	}

	// 积分是否足够
	private boolean isMemberPointEnough(MemberPoint memberPoint, Money principal,int dealLineNum) {
		if (memberPoint == null || principal == null) {
			logger.error("meberPoint or principal is null");
			return false;
		}
		int needPoint = tenderPointSetting.calcuTenderPoint(principal,dealLineNum);
		int canUsedPoint = memberPoint.getCanUsedPoint();
		return canUsedPoint > needPoint;
	}

	public Transfer prevCreateTransfer2(Long uid, Long tid) {
		Tender tender = tenderService.getByTidAndUid(tid, uid);
		if (tender == null) {
			logger.error("Find tender failed,tid=" + tid + ",uid=" + uid);
			return null;
		}
		Transfer transfer = createNewTranferObjectByTender2(tender, null);
		return transfer;
	}

	@Transactional
	public TransferResult createTransfer2(Long uid, Long tid,
			String transPassword) {
		TransferResult result = new TransferResult();
		Tender tender = tenderService.getByTidAndUid(tid, uid);
		Transfer transfer = createNewTranferObjectByTender2(tender,
				transPassword);
		// tstatus改为，转让中
		boolean bool = tenderService.updateTenderTstatus(tid,
				TenderTstatus.TRANSFING.getCode());
		if (!bool) {
			return result;
		}
		transferDao.create(transfer);
		result.setSuccess(true);
		return result;
	}

	private List<TenderReturn> recyclingTenderReturn(Long uid, Long tid) {
		TenderReturn queryCondition = new TenderReturn();
		queryCondition.setUid(uid);
		queryCondition.setTid(tid);
		queryCondition.setStatus(TenderReturnStatus.RECYCLING.getCode());
		List<TenderReturn> tenderReturnList = tenderReturnService
				.queryByUserCondition(queryCondition);
		return tenderReturnList;
	}

	private Transfer createNewTranferObjectByTender2(Tender tender,
			String transPassword) {
		Transfer transfer = buildInitialTransfer2(tender, transPassword);

		List<TenderReturn> tenderReturnList = recyclingTenderReturn(
				tender.getUid(), tender.getTid());
		checkTenderReturn(tenderReturnList);

		updateTransferPrincipalInterestNum(transfer, tenderReturnList);

		updateTransferFee(transfer, tenderReturnList, tender);

		return transfer;

	}

	/**
	 * 更新一个债权转让的价值、价格、利息管理费、利息管理费比例
	 * 
	 * @param transfer
	 * @param tenderReturnList
	 */
	private void updateTransferFee(Transfer transfer,
			List<TenderReturn> tenderReturnList, Tender tender) {
		Double transferValue = buildTransferValueAndUpdateTransferInfo(
				transfer, tenderReturnList);

		double pricePercent = buildPricePercent();

		transfer.setPricePercent(pricePercent);
		transfer.setTransValue(new Money(transferValue.longValue()));
		// 转让价格
		Double transferPrice = transferValue * pricePercent;
		Double lostPriceFeeDouble = transferValue - transferPrice;
		transfer.setLostPriceFee(new Money(lostPriceFeeDouble.longValue()));

		boolean isMoreThreeMonth = isMoreThreeMonth(tenderReturnList.get(0),
				tender);
		double transferFeePercent = buildTransferFeePercent(isMoreThreeMonth);
		Double transFee = transferPrice * transferFeePercent;
		transfer.setTransFeePercent(transferFeePercent);
		transfer.setTransFee(new Money(transFee.longValue()));
		transfer.setTransAmount(new Money(transferPrice.longValue()));

	}

	private double buildTransferFeePercent(boolean isMoreThreeMonth) {
		double transferFeePercent = 0.0;

		SysConfig config = null;
		if (isMoreThreeMonth) {
			// TODO 检测范围
			transferFeePercent = 0.0015;
			config = sysConfigService
					.getByKey(ConfigKeyEnum.TransferFeePercentLess);
		} else {
			// TODO 检查范围
			transferFeePercent = 0.003;
			config = sysConfigService
					.getByKey(ConfigKeyEnum.TransferFeePercentDefault);
		}
		if (config != null && StringUtils.isNotEmpty(StringUtils.trim(config.getValue()))) {
			String value = StringUtils.trim(config.getValue());
			try {
				transferFeePercent = Double.parseDouble(value);
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("parse transferFeePercent failed");
			}
			// 不能大过5%
			if (transferFeePercent > 0.5) {
				transferFeePercent = 0.5;
				logger.error("transferFeePercent more 0.5");
			}
		}
		return transferFeePercent;
	}

	private double buildPricePercent() {
		double pricePercent = 0.99;
		SysConfig config2 = sysConfigService
				.getByKey(ConfigKeyEnum.TransferPricePercent);
		String value2 = config2.getValue();
		try {
			pricePercent = Double.parseDouble(value2);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("buildPricePercent error");
		}
		// 不能小于80%
		if (pricePercent < 0.80) {
			pricePercent = 0.80;
			logger.error("pricePercent less 0.8");
		}
		return pricePercent;
	}

	/**
	 * 计算一个转让的价值,设置债权转让过期时间
	 * 
	 * @param transfer
	 * @param tenderReturnList
	 * @return
	 */
	private Double buildTransferValueAndUpdateTransferInfo(Transfer transfer,
			List<TenderReturn> tenderReturnList) {
		// 最近一期的还款
		TenderReturn recentTenderReturn = tenderReturnList.get(0);
		// 设置transfer的过期时间
		transfer.setExptime(recentTenderReturn.getTime());
		long monthInterestCent = recentTenderReturn.getAmount().getCent()
				- recentTenderReturn.getPrincipal().getCent();
		Money monthInterest = new Money(monthInterestCent);
		Double pastDays = caculatePastDays(recentTenderReturn);
		Double limitInterestCent = monthInterest.getCent() * pastDays / 30;
		Money interestManagementFee = chargeService.buildInterestManagementFee(
				transfer.getUid() + "",
				new Money(limitInterestCent.longValue()));
		// 债权价值=债权本金+(待结算利息-利息管理费)
		Double transferValue = transfer.getTransPrincipal().getCent()
				+ limitInterestCent - interestManagementFee.getCent();
		// transfer.setInterestManagementFee(interestManagementFee);
		// transfer.setInterestManagementFeePercent(interestManagementFeePercent);
		return transferValue;
	}

	/**
	 * 根据最近的一批tenderReturn，计算该笔回款已经产生的利息天数
	 * 
	 * @param recentTenderReturn
	 * @return
	 */
	private Double caculatePastDays(TenderReturn recentTenderReturn) {
		Date now = new Date();
		// 天数，做成Double，就相当于按小时、按分钟计算了
		Double days = DateUtil.getDayBetweenTwoDateDouble(recentTenderReturn
				.getTime().getTime(), now.getTime());
		// 一个月可能有31天，当天投标立即转让，会产生负数
		Double pastDays = 30.00 - days;
		if (pastDays < 0.0) {
			pastDays = 0.0;
		}
		return pastDays;
	}

	/**
	 * 根据一批投标回款信息，更新1个transfer的本金、利息和期数
	 * 
	 * @param transfer
	 * @param tenderReturnList
	 * @return 本金
	 */
	private void updateTransferPrincipalInterestNum(Transfer transfer,
			List<TenderReturn> tenderReturnList) {
		Money limitRepayAmount = new Money();
		Money limitPrincipal = new Money();
		int limitNum = 0;
		for (TenderReturn tempReturn : tenderReturnList) {
			limitRepayAmount.add(tempReturn.getAmount());
			limitPrincipal.add(tempReturn.getPrincipal());
			limitNum++;
		}
		transfer.setTransInterest(new Money(limitRepayAmount.getCent()
				- limitPrincipal.getCent()));
		transfer.setTransPrincipal(limitPrincipal);
		transfer.setTransNum(limitNum);
	}

	/**
	 * 检查一批投标回款,如果不合法，抛出异常
	 * 
	 * @param tenderReturnList
	 */
	private void checkTenderReturn(List<TenderReturn> tenderReturnList) {
		if (tenderReturnList == null || tenderReturnList.size() == 0) {
			logger.error("tenderReturnList is null or size =0");
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_parameters_error
							.name());
		}
	}

	/**
	 * 持有投标或债权是否超过了3个月
	 * 
	 * @param tender
	 * @return
	 */
	private boolean isMoreThreeMonth(TenderReturn tenderReturn, Tender tender) {
		return (tenderReturn.getNo() - tender.getStartNum()) >= 3;
	}

	/**
	 * 创建默认的“转让信息”
	 * 
	 * @param tender
	 * @param transPassword
	 * @return
	 */
	private Transfer buildInitialTransfer2(Tender tender, String transPassword) {
		Date now = new Date();
		Transfer transfer = new Transfer();
		transfer.setAddtime(now);
		transfer.setUptime(now);
		transfer.setLid(tender.getLid());
		transfer.setTid(tender.getTid());
		transfer.setUid(tender.getUid());
		LoanInfo loan = loanInfoDao.getLoanInfoById(tender.getLid());
		// 转让标的标题=贷款的标题
		transfer.setTitle(loan.getTitle());
		transfer.setRuid(null);
		transfer.setStatus(11);
		if (StringUtils.isNotBlank(transPassword)) {
			transfer.setTranspwd(transPassword);
		}
		return transfer;
	}

	public TransferResult acceptTransfer(final Long transferId,
			final Long acceptUserId, final String password) {
		TransferResult result = new TransferResult();
		TransactionTemplate transactionTemplate = new TransactionTemplate(
				transactionManager);
		transactionTemplate
				.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
		try {
			transactionTemplate.execute(new TransactionCallbackWithoutResult() {
				@Override
				protected void doInTransactionWithoutResult(
						TransactionStatus status) {
					// 并更新转让状态
					doAcceptTransferTransPay(transferId, acceptUserId, password);
					// 创建转让成功后的业务流水单据，并处理资金逻辑
					doTransferReturn(transferId, acceptUserId);
				}
			});

		} catch (BizException e) {
			result.setResultCode(e.getMessage());
			logger.error("acceptTransfer error transferId=" + transferId
					+ ",error code=" + e.getMessage());
		} catch (Exception e) {
			logger.error("acceptTransfer exception transferId=" + transferId, e);
		}
		result.setSuccess(true);
		return result;
	}

	/*private void doTransferPoint(){
		
	}*/
	@Transactional
	private void doTransferReturn(Long transferId, Long acceptUserId) {
		Transfer transfer = new Transfer();
		transfer.setId(transferId);
		transfer = transferDao.getTransfer(transfer);
		if (transfer == null) {
			logger.error("doTransferBiz error trander is null id=" + transferId);
			return;
		}

		Long tenderId = transfer.getTid();
		Tender tender = tenderService.getByTid(tenderId);
		if (tender == null) {
			logger.error("doTransferBiz error tender is null id=" + tenderId);
			return;
		}
		if (tender.getTstatus() != 11) {
			logger.error("doTransferBiz error tender status error tenderId="
					+ tenderId);
			return;
		}

		TenderReturn transferTenderReturn = new TenderReturn();
		// 创建状态为已回收的还款
		transferTenderReturn.setStatus(31);
		transferTenderReturn.setLid(transfer.getLid());
		transferTenderReturn.setNo(0);
		transferTenderReturn.setUid(transfer.getUid());
		transferTenderReturn.setPrincipal(transfer.getTransPrincipal());
		transferTenderReturn.setTid(transfer.getTid());
		Date now = new Date();
		transferTenderReturn.setTime(now);
		transferTenderReturn.setStartTime(now);
		transferTenderReturn.setIsFlow(0);
		transferTenderReturn.setReturnType(ReturnType.TRANSFER.getCode());
		transferTenderReturn.setUpdateTime(now);
		TenderReturn tenderReturn = new TenderReturn();
		tenderReturn.setUid(tender.getUid());
		tenderReturn.setTid(tender.getTid());
		tenderReturn.setStatus(21);

		List<TenderReturn> returnList = tenderReturnService
				.queryByUserCondition(tenderReturn);

		if (tender.getPtid() == null) {
			tender.setPtid(tenderId);
		}

		tender.setStartNum(tender.getNum() - transfer.getTransNum());
		tender.setTstatus(0);
		tender.setStatus(21);

		// 先取出原来投标人的账户，收服务费用
		String publishTenderUserAccount = tender.getUserAccount();
		Long publishUserId = tender.getUid();
		// 为债权转让-承接人，创建一条新的投标记录tender，uid应该是承接人的id
		tender.setUid(transfer.getRuid());
		// 承接人tender表的userName和account
		User acceptUser = userService.findById(acceptUserId + "");
		tender.setUserName(acceptUser.getUname());
		tender.setUserAccount(acceptUser.getAccountNo());
		tender.setAddtime(new Date());
		tender.setUptime(new Date());
		tenderService.updateTenderStatus(tender.getTid(),
				TenderStatus.REPAYED.getCode());
		tenderService.updateTenderTstatus(tender.getTid(),
				TenderTstatus.TRANSER_SUCCEED.getCode());
		// 插入前tid置空
		tender.setTid(null);
		tenderService.save(tender);

		List<Long> idList = new ArrayList<Long>();
		for (TenderReturn tempReturn : returnList) {
			idList.add(tempReturn.getId());
			tempReturn.setTid(tender.getTid());
			tempReturn.setUid(transfer.getRuid());

			tenderReturnService.create(tempReturn);
		}
		tenderReturnService.batchDeleteByIdList(idList);

		Money transAmount = transfer.getTransAmount();

		transferTenderReturn.setAmount(transAmount);
		// 创建回收流水，即转让成功的回款流水
		tenderReturnService.create(transferTenderReturn);

		int needPoint = tenderPointSetting.calcuTenderPoint(transAmount,returnList.size());
		memberPointService.cumulative(String.valueOf(publishUserId), needPoint, MemberPointLog.TypeEnum.TRANSFER_PUBLISH);
		memberPointService.cumulative(acceptUser.getUid(), needPoint, MemberPointLog.TypeEnum.TRANSFER_RECEIVE);
		
		TransInfo transInfo = new TransInfo();
		transInfo.setTransCode(TransCodeEnum.TXCODE_TRANSFER);
		transInfo.setSubTransCode(SubTransCodeEnum.SUB_TRANSFER_TRANSFER);
		transInfo.setTransAccountIn(publishTenderUserAccount);
		// 承接人向发布人支付transAmount钱
		transInfo.setTransAccountOut(acceptUser.getAccountNo());
		transInfo.setTransAmount(transAmount);
		transInfo.setTransCode(TransCodeEnum.TXCODE_TRANSFER);
		transInfo.setTransMemo("债权转让");

		
		AccountTransResult accountTransResult = remoteAccountTransFacade
				.transfer(transInfo);
		if (!accountTransResult.isSuccess()) {
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_common_error.name());
		}

		
		// 转让服务费
		chargeService.doChargeFromBalance(ChargeType.TRANSER_SERVICE_CHARGE,
				publishTenderUserAccount, publishUserId,
				transfer.getTransFee(), "债权转让服务费");
	}

	@Transactional
	private void doAcceptTransferTransPay(Long transferId, Long acceptUserId,
			String passsword) {
		Transfer transfer = new Transfer();
		transfer.setId(transferId);
		transfer = this.transferDao.getTransferForUpdate(transfer);
		if (transfer == null) {
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_parameters_error
							.name());
		}

		if (!transfer.getStatus().equals(11)) {
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_status_error.name());
		}
		if (transfer.getUid().equals(acceptUserId)) {
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_common_error.name(),
					"不能承接自己发布的债权");
		}
		// 存在承接密码的情况下，才可能报错
		String transpwd = transfer.getTranspwd();
		if (StringUtils.isNotEmpty(transpwd)) {
			if (!StringUtils.equals(transpwd, passsword)) {
				throw new BizException(
						TransferResult.ResultCodeEnum.transfer_password_error
								.name());
			}
		}
		AccountQueryResult queryResult = remoteAccountQueryFacade
				.getAccountByUserId(String.valueOf(acceptUserId));
		if (!queryResult.isSuccess()) {
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_common_error.name());
		}
		AccountVO accountVo = queryResult.getAccountVO();
		Money canUsebalance = accountVo.getCanUserBalance();
		if (canUsebalance.getCent() < transfer.getTransAmount().getCent()) {
			throw new BizException(
					TransferResult.ResultCodeEnum.transfer_common_error.name());
		}

		Date currentTime = new Date();

		transfer.setOktime(currentTime);
		transfer.setUptime(currentTime);
		transfer.setRuid(acceptUserId);
		transfer.setStatus(21);
		transferDao.update(transfer);
	}

	public PageVo searchListPage(PageVo form) {
		List<Map<String, Object>> list = transferDao.searchListPage(form);
		if (list != null && list.size() > 0) {
			checkStatus(list);
			List<Map<String, Object>> loanList = loanInfoService
					.batchList(list);
			List<Map<String, Object>> userList = userDao.batchList(list);
			TenderReturnServiceImpl.merge(list, loanList);
			merge(list, userList);
			form.setList(list);
		}
		return form;
	}

	public PageVo listPage(PageVo form) {
		List<Map<String, Object>> list = transferDao.listPage(form);
		if (list != null && list.size() > 0) {
			checkStatus(list);
			List<Map<String, Object>> loanList = loanInfoService
					.batchList(list);
			List<Map<String, Object>> userList = userDao.batchList(list);
			TenderReturnServiceImpl.merge(list, loanList);
			merge(list, userList);
			form.setList(list);
		}
		return form;
	}

	// 检查转让债权的状态
	private void checkStatus(List<Map<String, Object>> list) {
		for (Map<String, Object> transfer : list) {
			checkStatus(transfer);
		}

	}

	private Integer checkStatus(Map<String, Object> transfer) {
		Integer checkStatus = 0;
		Long exptime = null;
		Object exp = transfer.get("exptime");
		Integer status = (Integer) transfer.get("status");

		Long tid = MapUtils.getLong(transfer, "tid");
		Long id = Long.parseLong(transfer.get("id").toString());
		// 只检查正在转让的transfer
		if (exp != null && status.equals(11)) {
			exptime = ((Date) exp).getTime();
			Long updateTime = ((Date) transfer.get("uptime")).getTime();
			Long currentTime = System.currentTimeMillis();
			// 过期&正在转让，修改为“已过期”,tender的tstatus
			if (currentTime >= exptime) {
				transfer.put("status", 3);
				transferDao.simpleUpdateStatus(id, 3);
				tenderService.updateTenderTstatus(tid,
						TenderTstatus.INITIAL.getCode());
				logger.info("one transfer expired,id=" + id);
				checkStatus = 1;
			}
			// 没有过期&&不是同一天，重新计算债权转让
			else if (currentTime < exptime
					&& !DateUtil.isSameDay(currentTime, updateTime)) {
				Tender tender = tenderService.getByTid(tid);
				Transfer lastetTransfer = createNewTranferObjectByTender2(
						tender, null);
				transferDao.updateInterestAmount(lastetTransfer);
				logger.info("one transfer updated,new amount，id=" + id);
				checkStatus = 2;
			}
		}
		return checkStatus;
	}

	private void merge(List<Map<String, Object>> list,
			List<Map<String, Object>> userList) {
		int size = list.size();
		for (int index = 0; index < size; index++) {
			Map<String, Object> mainMap = list.get(index);
			Map<String, Object> userMap = TenderReturnServiceImpl
					.relationLoanMap(mainMap.get("uid"), userList, "uid");
			if (mainMap == null || userMap == null) {
				continue;
			}
			mainMap.put("uname", userMap.get("uname"));
		}
	}

	@Override
	public Map<String, Object> getTransferDetail(Long transferid) {
		Map<String, Object> transfer = transferDao.get(transferid);
		Integer checkStatus = checkStatus(transfer);
		if (checkStatus == 2) {
			transfer = transferDao.get(transferid);
		}
		Long lid = Long.parseLong(transfer.get("lid").toString());
		Map<String, Object> loan = loanInfoDao.get(lid);
		merge(transfer, loan, "loan_");
		return transfer;
	}

	// TODO 合并到MergeUtil
	private void merge(Map<String, Object> transfer, Map<String, Object> loan,
			String prefix) {
		Set<Entry<String, Object>> entrySet = loan.entrySet();
		for (Map.Entry<String, Object> entry : entrySet) {
			String newKey = prefix + entry.getKey();
			transfer.put(newKey, entry.getValue());
		}
	}

	// 把tender的状态改为“初始状态”，transfer的状态改为“已取消”
	@Transactional
	public void cancel(Long id, Long uid) {
		Transfer dtoTransfer = new Transfer();
		dtoTransfer.setId(id);
		Transfer tenderTransfer = transferDao.getTransferForUpdate(dtoTransfer);
		if (tenderTransfer.getStatus() != TransferStatus.TRANSFERING.getCode()) {
			throw new BizException("transfer_error", "只有正在转让的债权才能取消转让");
		}
		transferDao.updateStatus(id, uid, TransferStatus.TRANSFERING.getCode(),
				TransferStatus.CANCELED.getCode());
		tenderDao.updateTenderTstatus(tenderTransfer.getTid(),
				TenderTstatus.INITIAL.getCode());
	}

	@Transactional
	public void cancelTransferByTid(List<Long> tidList) {
		if (tidList == null || tidList.size() <= 0) {
			return;
		}
		List<Transfer> tenderTransferList = transferDao
				.getTransferListByTidListForUpdate(tidList,
						TransferStatus.TRANSFERING.getCode());
		cancelTranser(tenderTransferList);
	}

	private void cancelTranser(List<Transfer> tenderTransferList) {
		for (Transfer tenderTransfer : tenderTransferList) {
			transferDao.updateStatus(tenderTransfer.getId(),
					tenderTransfer.getUid(),
					TransferStatus.TRANSFERING.getCode(),
					TransferStatus.CANCELED.getCode());
			tenderDao.updateTenderTstatus(tenderTransfer.getTid(),
					TenderTstatus.INITIAL.getCode());
		}
	}

	/**
	 * 根据lid，取消这个lid下的转让中的债权
	 * 
	 * @param lid
	 */
	@Transactional
	public void cancelTransferByLid(Long lid) {
		Transfer dtoTransfer = new Transfer();
		dtoTransfer.setLid(lid);
		dtoTransfer.setStatus(TransferStatus.TRANSFERING.getCode());
		List<Transfer> tenderTransferList = transferDao
				.getTransferListByLidForUpdate(dtoTransfer);
		cancelTranser(tenderTransferList);
	}

	// 是否可以承接一个债权
	@Override
	public boolean canAccept(Long transferid, Long uid, String paypwd,
			String transpwd) {
		// 支付密码是否正确
		boolean paypwdRight = commonService.checkPaypwd(paypwd, uid);
		if (!paypwdRight) {
			return false;
		}
		// 债权转让状态是否正常
		Map<String, Object> transfer = transferDao.get(transferid);
		int check = checkStatus(transfer);
		if (check != 0) {
			return false;
		}

		// 部分条件检查，在做具体业务的时候，才检查更多条件,参见doAcceptTransferTransPay
		return true;
	}

	// //////////////////////////////////////////////////////////////////
	// 第1版的债权转让公式等
	@Deprecated
	public Transfer prevCreateTransfer(Long uid, Long tid) {
		Tender tender = this.tenderService.getByTidAndUid(tid, uid);
		if (tender == null) {
			logger.error("Find tender failed,tid=" + tid + ",uid=" + uid);
		}
		// status还款中， tstatus初始
		if (!canTransfer(tender)) {
			return null;
		}
		Transfer transfer = createNewTranferObjectByTender(tender, null);
		return transfer;
	}

	@Deprecated
	private Transfer createNewTranferObjectByTender(Tender tender,
			String transPassword) {

		Transfer transfer = buildInitialTransfer(tender, transPassword);

		Date now = new Date();

		TenderReturn queryCondition = new TenderReturn();
		queryCondition.setUid(tender.getUid());
		queryCondition.setTid(tender.getTid());
		queryCondition.setStatus(21);
		List<TenderReturn> tenderReturnList = tenderReturnService
				.queryByUserCondition(queryCondition);
		checkTenderReturn(tenderReturnList);

		updateTransferPrincipalInterestNum(transfer, tenderReturnList);

		TenderReturn tenderReturn = tenderReturnList.get(0);
		Money monthInterest = new Money(tenderReturn.getAmount().getCent()
				- tenderReturn.getPrincipal().getCent());
		int days = DateUtil.getDayBetweenTwoDate(tenderReturn.getTime()
				.getTime(), now.getTime());
		// 一个月可能有31天，当天投标立即转让，会产生负数
		int pastDays = 30 - days;
		if (pastDays < 0) {
			pastDays = 0;
		}
		Money limitPrincipal = transfer.getTransPrincipal();
		long limitInterestCent = monthInterest.getCent() * pastDays / 30;
		if (tenderReturn.getNo() == 1) {
			transfer.setTransAmount(new Money(limitPrincipal.getCent()
					+ limitInterestCent - limitInterestCent / 3));
			transfer.setTransFee(new Money(limitInterestCent / 3));
		} else {
			transfer.setTransAmount(new Money(limitPrincipal.getCent()
					+ limitInterestCent - monthInterest.getCent() / 3));
			transfer.setTransFee(new Money(monthInterest.getCent() / 3));
		}

		return transfer;

	}

	@Deprecated
	private Transfer buildInitialTransfer(Tender tender, String transPassword) {
		Date now = new Date();
		Transfer transfer = new Transfer();
		transfer.setAddtime(now);
		transfer.setExptime(DateUtil.addDay(now, 3));
		transfer.setLid(tender.getLid());
		transfer.setTid(tender.getTid());
		transfer.setUid(tender.getUid());
		LoanInfo loan = loanInfoDao.getLoanInfoById(tender.getLid());
		// 转让标的标题=贷款的标题
		transfer.setTitle(loan.getTitle());
		transfer.setRuid(null);
		transfer.setStatus(11);
		if (StringUtils.isNotBlank(transPassword)) {
			transfer.setTranspwd(transPassword);
		}
		transfer.setUptime(new Date());
		return transfer;
	}

	private boolean canTransfer(Tender tender) {
		return (tender.getStatus() == 21 && tender.getTstatus() == 0);
	}

	@Deprecated
	public TransferResult createTransfer(Long uid, Long tid,
			String transPassword) {
		TransferResult result = new TransferResult();
		Tender tender = this.tenderService.getByTidAndUid(tid, uid);
		// status还款中， tstatus初始
		if (!canTransfer(tender)) {
			return result;
		}

		Transfer transfer = createNewTranferObjectByTender(tender,
				transPassword);

		boolean bool = tenderService.updateTenderTstatus(tid, 11);
		if (!bool) {
			return result;
		}
		this.transferDao.create(transfer);

		result.setSuccess(true);
		return result;

	}
}
